package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"reflect"
	"time"
)

// 返回数据格式  {"books":["西游记","红楼梦","三国演义"]}
func getBookJson(ctx *gin.Context) {
	ctx.JSON(200, gin.H{
		"books": []string{"西游记", "红楼梦", "三国演义"},
	})
	fmt.Println(time.Now())
}

// 这里获取的数据key-ctx.PostForm("user") user是post请求增加参数
func auth(ctx *gin.Context) {
	user := ctx.PostForm("user")
	password := ctx.PostForm("password")

	if user == "admin" && password == "admin" {
		ctx.String(http.StatusOK, "ok")
	} else {
		ctx.String(http.StatusOK, "fail")
	}
}

func getOneBook(ctx *gin.Context) {
	ctx.JSON(200, gin.H{
		"data": "查看某个书籍",
	})
}

func request(context *gin.Context) {
	fmt.Println(context.Request.Method)                                // get 请求
	fmt.Println(context.Request.URL)                                   // 获取请求路径 request
	fmt.Println(context.Request.RemoteAddr)                            // 获取请求地址 IP和端口
	fmt.Println(context.ClientIP())                                    // 直接获取请求IP
	fmt.Println(context.Request.Header)                                // 获取请求头信息
	fmt.Println("User-Agent = ", context.Request.Header["User-Agent"]) // 直接获取具体的请求头
}

func pathParam(context *gin.Context) {
	// pathParam/:name/:id 获取路径绑定的参数 实际请求pathParam/:user/:1
	name := context.Param("name")
	id := context.Param("id")
	fmt.Println(name, id)
	fmt.Println(reflect.ValueOf(id))

	context.JSON(200, gin.H{
		"name": name,
		"id":   id,
	})
}

func queryParam(context *gin.Context) {
	// queryParam?name 查询参数? name=username
	//获取name参数,通过Query获取的参数值是String类型
	name := context.Query("name")

	//获取name参数,跟Query函数的区别是，可以通过第⼆个参数设置默认值
	defaultName := context.DefaultQuery("name", "DefaultQuery")

	// 获取user参数,通过GetQuery获取的参数值也是String类型
	// 区别是GetQuery返回两个参数，第⼀个是参数值，第⼆个参数是参数是否存在的bool值，可以⽤来判断参数是否存在
	// GetQuery函数，判断参数是否存在的逻辑是，参数值为空，参数也算存在，只有没有提交参数，才算参数不存在
	getQuery, ok := context.GetQuery("name")
	if ok {
		fmt.Println("ok", ok)
	}
	context.JSON(http.StatusOK, gin.H{
		"name":        name,
		"defaultName": defaultName,
		"getQuery":    getQuery,
	})
}

type User struct {
	// json:"name" 数据格式为json格式，并且json字段名为name 进行json转换时按照定义的字段名转换
	// form:"name" 表单参数名为name
	Name string `json:"name" form:"name"`
	Age  int    `json:"age" form:"age"`
}

func queryUser(context *gin.Context) {

	user := User{}

	//通过ShouldBind函数，将请求参数绑定到struct对象，处理json请求代码是⼀样的。
	//如果是post请求则根据Content-Type判断，接收的是json数据，还是普通的http请求参数
	err := context.ShouldBind(&user)
	if err == nil {
		//绑定成功，打印请求参数
		fmt.Println(user)
	}

	context.JSON(http.StatusOK, gin.H{
		"msg":             "parser Success",
		"请求的content-type": context.ContentType(),
		"解构后的数据":          user,
	})
}

func main() {
	// 获取路由对象
	route := gin.Default()

	// 接收get请求 只接收路径是/index 返回string类型数据
	// context 上下文对象
	route.GET("/index", func(context *gin.Context) {
		context.String(http.StatusOK, "hello world index")
	})

	// 接收get请求 只接受路径是getBooks 返回是json数据
	route.GET("/getBooks", getBookJson)

	// 接收post请求 post请求可以借助测试接口工具试验
	route.POST("/auth", auth)

	// 路由分组嵌套一层嵌套 请求路径 books/
	RoutingGrouping := route.Group("/books")
	{
		RoutingGrouping.GET("/show", getBookJson)
		RoutingGrouping.GET("/getOne", getOneBook)
	}

	// 路由分组嵌套两层嵌套
	api := route.Group("/api")
	{
		bookRouter := api.Group("/books")
		{
			bookRouter.GET("/show", getOneBook)
			bookRouter.GET("/getOne", getOneBook)
		}
	}

	// 获取基本请求数据
	route.GET("request", request)

	// 获取路径参数
	route.GET("pathParam/:name/:id", pathParam)

	// 获取查询参数
	route.GET("queryParam", queryParam)

	// shouldBind 函数
	route.POST("/user", queryUser)

	// 端口监听
	_ = route.Run(":8080")
}
